package com.h3c.ptability.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.eos.common.util.IdWorker;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.eos.common.util.Result;
import com.h3c.ptability.cache.UserCache;
import com.h3c.ptability.dto.OptionsDTO;
import com.h3c.ptability.dto.PtDeptDTO;
import com.h3c.ptability.entity.PtAllWorker;
import com.h3c.ptability.entity.PtApp;
import com.h3c.ptability.entity.PtDept;
import com.h3c.ptability.entity.PtUserDept;
import com.h3c.ptability.mapper.PtUserDeptMapper;
import com.h3c.ptability.service.*;
import com.h3c.ptability.dto.PtUserDeptDTO;
import com.h3c.ptability.utils.*;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Copyright (C), 2020-2020, h3c
 * FileName: PtUserDeptServiceImpl
 *
 * @Author: l22886
 * @Date: 2022-03-14
 * Description: pt_user_dept serviceImpl
 * Version: 1.0
 */
@Slf4j
@Service
public class PtUserDeptServiceImpl extends ServiceImpl<PtUserDeptMapper, PtUserDept> implements IPtUserDeptService {

    @Resource
    private PtUserDeptMapper ptUserDeptMapper;

    @Resource
    private IPtAppService ptAppService;

    @Resource
    private IPtDeptService ptDeptService;

    @Resource
    private IPtAllWorkerService ptAllWorkerService;

    @Resource
    DeptTree deptTree;
    /**
     * @title: selectFuzzyByDto
     * @description: 模糊查询操作
     * @params: [ dto ]
     * @return: java.util.List
     * @createTime: 2022-03-14
     * @version: 1.0
     * @author: l22886
     */
    @Override
    public List<PtUserDeptDTO> selectFuzzyByDto(PtUserDeptDTO dto) {
        //List<PtUserDept> list = ptUserDeptMapper.selectByExample(initFuzzyExample(dto));
        List<PtUserDept> list = ptUserDeptMapper.queryListByFuzzy(JSONObject.parseObject(JSONObject.toJSONString(dto),PtUserDept.class));
        return JSONArray.parseArray(JSONArray.toJSONString(list), PtUserDeptDTO.class);
    }

    /**
     * @title: selectByDto
     * @description: 精确查询操作
     * @params: [ dto ]
     * @return: java.util.List
     * @createTime: 2022-03-14
     * @version: 1.0
     * @author: l22886
     */
    @Override
    public List<PtUserDeptDTO> selectByDto(PtUserDeptDTO dto) {
        //List<PtUserDept> list = ptUserDeptMapper.selectByExample(initExample(dto));
        List<PtUserDept> list = ptUserDeptMapper.queryList(JSONObject.parseObject(JSONObject.toJSONString(dto),PtUserDept.class));
        return JSONArray.parseArray(JSONArray.toJSONString(list), PtUserDeptDTO.class);
    }

    /**
     * @title: insertDto
     * @description: 插入操作
     * @params: [ dto ]
     * @return: Integer
     * @createTime: 2022-03-14
     * @version: 1.0
     * @author: l22886
     */
    @Override
    public Integer insertDto(PtUserDeptDTO dto) {
        //if (null == dto.getId() || "".equals(dto.getId())) {
        //    String pkId = idWorker.nextId() + "";
        //    dto.setId(pkId);
        //}
        return ptUserDeptMapper.insertPtUserDept(JSONObject.parseObject(JSON.toJSONString(dto), PtUserDept.class));
    }

    /**
     * @title: updateDto
     * @description: 修改操作
     * @params: [ dto ]
     * @return: Integer
     * @createTime: 2022-03-14
     * @version: 1.0
     * @author: l22886
     */
    @Override
    public Integer updateDto(PtUserDeptDTO dto) {
        //if (null != dto && null != dto.getId() && !"".equals(dto.getId())) {
            return ptUserDeptMapper.updatePtUserDept(JSONObject.parseObject(JSON.toJSONString(dto), PtUserDept.class));
            //return ptUserDeptMapper.updateByPrimaryKey(JSONObject.parseObject(JSON.toJSONString(dto), PtUserDept.class));
        //} else {
        //    return 0;
        //}
    }

    /**
     * @title: deleteDto
     * @description: 删除操作
     * @params: [ dto ]
     * @return: Integer
     * @createTime: 2022-03-14
     * @version: 1.0
     * @author: l22886
     */
    @Override
    public Integer deleteDto(PtUserDeptDTO dto) {
        //if (null != dto && null != dto.getId() && !"".equals(dto.getId())) {
            return ptUserDeptMapper.deletePtUserDept(JSONObject.parseObject(JSON.toJSONString(dto), PtUserDept.class));
            //return ptUserDeptMapper.deleteByPrimaryKey(dto.getId());
        //} else {
        //    return 0;
        //}
    }

    @Override
    public List<Integer> getUserDeptPermissionWithDeptLevel(String appId, String domainAccount, Integer deptLevel) {
        PtApp ptApp = ptAppService.getById(appId);
        Assert.notNull(ptApp, () -> {
            throw new AppBusinessException("不存在此应用");
        });
        PtAllWorker allWorker = ptAllWorkerService.getOne(new QueryWrapper<PtAllWorker>().lambda()
                .eq(PtAllWorker::getDomainAccount, domainAccount));
        String userId = allWorker.getWorkerId();
        List<Integer> deptList = getBaseMapper().getAuthorityDeptIds("%" + userId + "%", ptApp.getAuthCenterId(), deptLevel);
        return deptList.stream().distinct().collect(Collectors.toList());
    }


    @Override
    public List<String> getUserDeptPermission(String userId, String domainAccount, String appId) {
        PtApp ptApp = ptAppService.getById(appId);
        Assert.notNull(ptApp, () -> {
            throw new AppBusinessException("不存在此应用");
        });
        LambdaQueryWrapper<PtUserDept> queryWrapper = new QueryWrapper<PtUserDept>().lambda();
        LambdaQueryWrapper<PtDept> deptQueryWrapper = new QueryWrapper<PtDept>().lambda();
        if (StringUtils.isNotBlank(userId)) {
            queryWrapper.select(PtUserDept::getDeptId)
                    .eq(PtUserDept::getAppId, ptApp.getAuthCenterId())
                    .apply("FIND_IN_SET ('" + userId + "',user_ids)");
            deptQueryWrapper.apply("FIND_IN_SET ('" + userId + "',dept_manager_id)");
        } else if (StringUtils.isNotBlank(domainAccount)) {
            PtAllWorker allWorker = ptAllWorkerService.getOne(new QueryWrapper<PtAllWorker>().lambda()
                    .eq(PtAllWorker::getDomainAccount, domainAccount)
            );
            if (Objects.isNull(allWorker)) {
                return new ArrayList<>();
            }
            queryWrapper.select(PtUserDept::getDeptId)
                    .eq(PtUserDept::getAppId, ptApp.getAuthCenterId())
                    .apply("FIND_IN_SET ('" + allWorker.getWorkerId() + "',user_ids)");
            deptQueryWrapper.apply("FIND_IN_SET ('" + allWorker.getWorkerId() + "',dept_manager_id)");
        } else {
            queryWrapper.select(PtUserDept::getDeptId)
                    .eq(PtUserDept::getAppId, ptApp.getAuthCenterId())
                    .apply(UserCache.getLoginUserId() != null, "FIND_IN_SET ('" + UserCache.getLoginUserId() + "',user_ids)");
            deptQueryWrapper.apply("FIND_IN_SET ('" + UserCache.getLoginUserId() + "',dept_manager_id)");
        }
        List<String> deptUserAllowIds = list(queryWrapper).stream().map(s-> String.valueOf(s.getDeptId())).collect(Collectors.toList());
        List<String> deptAllowIds = ptDeptService.list(deptQueryWrapper).stream().filter(s -> s.getDeptStatus() == 1).map(s-> String.valueOf(s.getDeptId())).collect(Collectors.toList());
        List<OptionsDTO> deptTree = ptDeptService.queryDeptTreeSelection(null);
        ArrayList<String> childrenDeptIds = new ArrayList<>();
        OptionsDTO root = new OptionsDTO();
        root.setValue("50040000");
        root.setDeptNameChain("新华三");
        root.setLabel("新华三");
        root.setChildren(deptTree);
        if (deptAllowIds.size() > 0) {
            for (String deptAllowId : deptAllowIds) {
                OptionsDTO node = TreeUtils.getNode(root, String.valueOf(deptAllowId));
                log.info("deptAllowId:,node对象:, {}, {}", deptAllowId, node);
                TreeUtils.getChildrenDept(node, childrenDeptIds);
                deptUserAllowIds.addAll(childrenDeptIds);
            }
        }
        deptUserAllowIds.addAll(deptAllowIds);
        return deptUserAllowIds.stream().distinct().collect(Collectors.toList());
    }



    @Override
    public List<String> getUserDeptPermissionforHrSign(String userId, String domainAccount, String appId) {
        PtApp ptApp = ptAppService.getById(appId);
        Assert.notNull(ptApp, () -> {
            throw new AppBusinessException("不存在此应用");
        });
        LambdaQueryWrapper<PtUserDept> queryWrapper = new QueryWrapper<PtUserDept>().lambda();
        LambdaQueryWrapper<PtDept> deptQueryWrapper = new QueryWrapper<PtDept>().lambda();
        if (StringUtils.isNotBlank(userId)) {
            queryWrapper.select(PtUserDept::getDeptId)
                    .eq(PtUserDept::getAppId, ptApp.getAppId())
                    .apply("FIND_IN_SET ('" + userId + "',user_ids)");
            deptQueryWrapper.apply("FIND_IN_SET ('" + userId + "',dept_manager_id)");
        } else if (StringUtils.isNotBlank(domainAccount)) {
            PtAllWorker allWorker = ptAllWorkerService.getOne(new QueryWrapper<PtAllWorker>().lambda()
                    .eq(PtAllWorker::getDomainAccount, domainAccount)
            );
            if (Objects.isNull(allWorker)) {
                return new ArrayList<>();
            }
            queryWrapper.select(PtUserDept::getDeptId)
                    .eq(PtUserDept::getAppId, ptApp.getAppId())
                    .apply("FIND_IN_SET ('" + allWorker.getWorkerId() + "',user_ids)");
            deptQueryWrapper.apply("FIND_IN_SET ('" + allWorker.getWorkerId() + "',dept_manager_id)");
        } else {
            queryWrapper.select(PtUserDept::getDeptId)
                    .eq(PtUserDept::getAppId, ptApp.getAppId())
                    .apply(UserCache.getLoginUserId() != null, "FIND_IN_SET ('" + UserCache.getLoginUserId() + "',user_ids)");
            deptQueryWrapper.apply("FIND_IN_SET ('" + UserCache.getLoginUserId() + "',dept_manager_id)");
        }
        List<String> deptUserAllowIds = list(queryWrapper).stream().map(s-> String.valueOf(s.getDeptId())).collect(Collectors.toList());
        List<String> deptAllowIds = ptDeptService.list(deptQueryWrapper).stream().filter(s -> s.getDeptStatus() == 1).map(s-> String.valueOf(s.getDeptId())).collect(Collectors.toList());
        List<OptionsDTO> deptTree = ptDeptService.queryDeptTreeSelection(null);
        ArrayList<String> childrenDeptIds = new ArrayList<>();
        OptionsDTO root = new OptionsDTO();
        root.setValue("50040000");
        root.setDeptNameChain("新华三");
        root.setLabel("新华三");
        root.setChildren(deptTree);
        if (deptAllowIds.size() > 0) {
            for (String deptAllowId : deptAllowIds) {
                OptionsDTO node = TreeUtils.getNode(root, String.valueOf(deptAllowId));
                log.info("deptAllowId:,node对象:, {}, {}", deptAllowId, node);
                TreeUtils.getChildrenDept(node, childrenDeptIds);
                deptUserAllowIds.addAll(childrenDeptIds);
            }
        }
        deptUserAllowIds.addAll(deptAllowIds);
        return deptUserAllowIds.stream().distinct().collect(Collectors.toList());
    }

    @Override
    public List<String> getUserDeptPermissionHrSign(String userId, String domainAccount, String appId) {
        PtApp ptApp = ptAppService.getById(appId);
        Assert.notNull(ptApp, () -> {
            throw new AppBusinessException("不存在此应用");
        });
        LambdaQueryWrapper<PtUserDept> queryWrapper = new QueryWrapper<PtUserDept>().lambda();
        if (StringUtils.isNotBlank(userId)) {
            queryWrapper.select(PtUserDept::getDeptId)
                    .eq(PtUserDept::getAppId, ptApp.getAppId())
                    .apply("FIND_IN_SET ('" + userId + "',user_ids)");
        } else if (StringUtils.isNotBlank(domainAccount)) {
            PtAllWorker allWorker = ptAllWorkerService.getOne(new QueryWrapper<PtAllWorker>().lambda()
                    .eq(PtAllWorker::getDomainAccount, domainAccount)
            );
            if (Objects.isNull(allWorker)) {
                return new ArrayList<>();
            }
            queryWrapper.select(PtUserDept::getDeptId)
                    .eq(PtUserDept::getAppId, ptApp.getAppId())
                    .apply("FIND_IN_SET ('" + allWorker.getWorkerId() + "',user_ids)");
        } else {
            queryWrapper.select(PtUserDept::getDeptId)
                    .eq(PtUserDept::getAppId, ptApp.getAppId())
                    .apply(UserCache.getLoginUserId() != null, "FIND_IN_SET ('" + UserCache.getLoginUserId() + "',user_ids)");
        }
        List<String> deptUserAllowIds = list(queryWrapper).stream().map(s-> String.valueOf(s.getDeptId())).collect(Collectors.toList());
        return deptUserAllowIds.stream().distinct().collect(Collectors.toList());
    }


    /**
     * @title: initFuzzyExample
     * @description: 初始化 模糊查询 example
     * @params: [ dto ]
     * @return: tk.mybatis.mapper.entity.Example
     * @createTime: 2022-03-14
     * @version: 1.0
     * @author: l22886
     */
    private Example initFuzzyExample(PtUserDeptDTO dto) {
        Example example = InitExampleOrderByUtils.initExampleOrderBy(PtUserDept.class, dto.getOrderBy());
        Example.Criteria criteriaName = example.createCriteria();
        if (null != dto) {
            if (null != dto.getUserId() && !"".equals(dto.getUserId())) {
                criteriaName.andLike("UserId", "%" + dto.getUserId() + "%");
            }
            if (null != dto.getAppId() && !"".equals(dto.getAppId())) {
                criteriaName.andLike("AppId", "%" + dto.getAppId() + "%");
            }
            if (null != dto.getDeptId() && !"".equals(dto.getDeptId())) {
                criteriaName.andLike("DeptId", "%" + dto.getDeptId() + "%");
            }
            if (null != dto.getCreateTime() && !"".equals(dto.getCreateTime())) {
                criteriaName.andLike("CreateTime", "%" + dto.getCreateTime() + "%");
            }
            if (null != dto.getCreatorId() && !"".equals(dto.getCreatorId())) {
                criteriaName.andLike("CreatorId", "%" + dto.getCreatorId() + "%");
            }
        }
        return example;
    }

    /**
     * @title: initExample
     * @description: 初始化 精确查询 example
     * @params: [ dto ]
     * @return: tk.mybatis.mapper.entity.Example
     * @createTime: 2022-03-14
     * @version: 1.0
     * @author: l22886
     */
    private Example initExample(PtUserDeptDTO dto) {
        Example example = InitExampleOrderByUtils.initExampleOrderBy(PtUserDept.class, dto.getOrderBy());
        Example.Criteria criteriaName = example.createCriteria();
        if (null != dto) {
            if (null != dto.getUserId() && !"".equals(dto.getUserId())) {
                criteriaName.andEqualTo("UserId", dto.getUserId());
            }
            if (null != dto.getAppId() && !"".equals(dto.getAppId())) {
                criteriaName.andEqualTo("AppId", dto.getAppId());
            }
            if (null != dto.getDeptId() && !"".equals(dto.getDeptId())) {
                criteriaName.andEqualTo("DeptId", dto.getDeptId());
            }
            if (null != dto.getCreateTime() && !"".equals(dto.getCreateTime())) {
                criteriaName.andEqualTo("CreateTime", dto.getCreateTime());
            }
            if (null != dto.getCreatorId() && !"".equals(dto.getCreatorId())) {
                criteriaName.andEqualTo("CreatorId", dto.getCreatorId());
            }
        }
        return example;
    }

    @Override
    @SneakyThrows
    public PtDeptDTO getAuthorizeChildTree(String appId, String workerId, Boolean flag) {
        if (org.apache.commons.lang3.StringUtils.isBlank(appId)) {
            throw new AppBusinessException("appId不能为空");
        }
        if (org.apache.commons.lang3.StringUtils.isBlank(workerId)) {
            throw new AppBusinessException("工号不能为空");
        }
        PtDeptDTO childTree = deptTree.getChildTree(BusiEnumDefine.H3C_CODE);
        if (childTree == null || CollectionUtils.isEmpty(childTree.getChildren())){
            return null;
        }

        if (!flag) {
            reduceParent(childTree);
            //return childTree.getChildren().stream().collect(Collectors.toList());
            return childTree;
        }
        List<String> deptIds = getUserDeptPermissionforHrSign(workerId, null, appId);
        CountDownLatch latch = new CountDownLatch(deptIds.size());
        List<PtUserDept> ptUserDepts = new ArrayList<>();
        for (String deptId : deptIds) {
            Thread thread = new Thread(() -> {
                try {
                    PtUserDept ptUserDept = new PtUserDept();
                    ptUserDept.setAppId(appId);
                    ptUserDept.setDeptId(Integer.valueOf(deptId));
                    ptUserDept.setUserIds(workerId);
                    ptUserDept.setUserNames(ptAllWorkerService.getById(workerId).getWorkerName());
                    ptUserDepts.add(ptUserDept);
                } finally {
                    latch.countDown();
                }
            });
            SpringUtil.getBean(ThreadPoolService.class).submitTask(thread);
        }
        latch.await();
        Map<Integer, PtUserDept> allAuthorizeDeptMap = ptUserDepts.stream().collect(
                Collectors.toMap(PtUserDept::getDeptId, dept -> dept));
        judgeAuthorizeDeptNoTree(childTree, workerId, allAuthorizeDeptMap);

        reduceUnAuthorizedParent(childTree);
        return childTree;
    }

    @Override
    public List<PtDeptDTO> changeRootToChildList(PtDeptDTO root){
        if (root == null || CollectionUtils.isEmpty(root.getChildren())){
            return new ArrayList<>();
        }
        return new ArrayList<>(root.getChildren());
    }

    public void reduceParent(PtDeptDTO childTree){
        if (!CollectionUtils.isEmpty(childTree.getChildren())){
            List<PtDeptDTO> childList = childTree.getChildren().stream().peek(dept -> dept.setParent(null)).collect(Collectors.toList());
            childTree.setChildren(childList);
            for (PtDeptDTO ptDeptDTO : childList) {
                reduceParent(ptDeptDTO);
            }
        }
    }

    public void judgeAuthorizeDeptNoTree(PtDeptDTO root, String empCode, Map<Integer, PtUserDept> allAuthorizeDeptMap){
        if (!CollectionUtils.isEmpty(root.getChildren())){
            for (PtDeptDTO child : root.getChildren()) {
                judgeAuthorizeDeptNoTree(child, empCode, allAuthorizeDeptMap);
            }
        }

        boolean parentHasAuthorize = false;
        root.setHasChildren(false);
        if (allAuthorizeDeptMap.containsKey(root.getDeptId())){
            String userNames = allAuthorizeDeptMap.get(root.getDeptId()).getUserNames();
            String userIds = allAuthorizeDeptMap.get(root.getDeptId()).getUserIds();
            root.setUserNames(userNames);
            root.setUserIds(userIds);
            root.setHasAuthorize(true);
            root.setCanAuthorize(true);
            parentHasAuthorize = true;
        }

        allAuthorizeDeptNoTree(root, parentHasAuthorize, allAuthorizeDeptMap);
    }

    public void reduceUnAuthorizedParent(PtDeptDTO childTree){
        if (!CollectionUtils.isEmpty(childTree.getChildren())){
            List<PtDeptDTO> childList = childTree.getChildren().stream().filter(dept -> dept.getHasAuthorize() != null && dept.getHasAuthorize()).peek(dept -> dept.setParent(null)).collect(Collectors.toList());
            childTree.setChildren(childList);
            for (PtDeptDTO ptDeptDTO : childList) {
                reduceUnAuthorizedParent(ptDeptDTO);
            }
        }
    }

    public void allAuthorizeDeptNoTree(PtDeptDTO root, boolean parentHasAuthorize, Map<Integer, PtUserDept> allAuthorizeDeptMap){
        if (root.getParent() != null) {
            root = root.getParent();
            if (root.getHasAuthorize() != null && root.getHasAuthorize()){
                root.setCanAuthorize(allAuthorizeDeptMap.containsKey(root.getDeptId()));
                allAuthorizeDeptNoTree(root, true, allAuthorizeDeptMap);
            } else {
                if (parentHasAuthorize){
                    root.setHasAuthorize(true);
                } else {
                    if (allAuthorizeDeptMap.containsKey(root.getDeptId())){
                        String userNames = allAuthorizeDeptMap.get(root.getDeptId()).getUserNames();
                        String userIds = allAuthorizeDeptMap.get(root.getDeptId()).getUserIds();
                        root.setUserNames(userNames);
                        root.setUserIds(userIds);
                        root.setHasAuthorize(true);
                        parentHasAuthorize = true;
                    }
                }
                root.setCanAuthorize(allAuthorizeDeptMap.containsKey(root.getDeptId()));
                allAuthorizeDeptNoTree(root, parentHasAuthorize, allAuthorizeDeptMap);
            }
        }
    }
}
